package com.jiangyg.mall.product.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jiangyg.mall.core.constant.CoreConstant;
import com.jiangyg.mall.core.enums.Logic;
import com.jiangyg.mall.core.support.restful.Criteria;
import com.jiangyg.mall.core.support.restful.Pagination;
import com.jiangyg.mall.core.utils.Logger;
import com.jiangyg.mall.core.utils.bean.BeanUtils;
import com.jiangyg.mall.db.mybatis.BaseServiceImpl;
import com.jiangyg.mall.product.constant.ColumnConstant;
import com.jiangyg.mall.product.dao.SkuInfoDao;
import com.jiangyg.mall.product.dao.SkuSaleAttrValueDao;
import com.jiangyg.mall.product.dao.SpuInfoDao;
import com.jiangyg.mall.product.dao.SpuInfoDescDao;
import com.jiangyg.mall.product.dto.SpuAttrgroupDTO;
import com.jiangyg.mall.product.entity.SkuInfo;
import com.jiangyg.mall.product.entity.SkuSaleAttrValue;
import com.jiangyg.mall.product.entity.SpuInfoDesc;
import com.jiangyg.mall.product.enums.Published;
import com.jiangyg.mall.product.vo.SkuBriefInfoVO;
import com.jiangyg.mall.product.vo.SkuInfoVO;
import com.jiangyg.mall.product.vo.SkuSaleAttrValueVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.task.TaskExecutor;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

@Slf4j
@Service
public class SkuServiceImpl extends BaseServiceImpl<SkuInfoDao, SkuInfo> implements SkuService {

    /**
     * 线程池
     */
    private final TaskExecutor executor;

    private final SpuInfoDao spuInfoDao;

    private final SpuInfoDescDao spuInfoDescDao;

    private final SkuSaleAttrValueDao skuSaleAttrValueDao;

    @Autowired
    public SkuServiceImpl(SkuInfoDao baseMapper,
                          SpuInfoDao spuInfoDao,
                          SpuInfoDescDao spuInfoDescDao,
                          SkuSaleAttrValueDao skuSaleAttrValueDao,
                          @Qualifier(CoreConstant.ASYNC_EXECUTOR) TaskExecutor executor) {
        super(baseMapper);
        this.executor = executor;
        this.spuInfoDao = spuInfoDao;
        this.spuInfoDescDao = spuInfoDescDao;
        this.skuSaleAttrValueDao = skuSaleAttrValueDao;
    }

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public Pagination<SkuInfoVO> selectPagination(Pagination<SkuInfoVO> pagination) throws Exception {
        // 价格范围处理
        {
            if (CollectionUtils.isNotEmpty(pagination.getCriterias())) {
                final List<Criteria> criterias = pagination.getCriterias();
                criterias.forEach(criteria -> {
                    if (!StringUtils.equals(criteria.getName(), "price") || criteria.getValues() == null) {
                        return;
                    }
                    final Object[] values = criteria.getValues();
                    if (values.length >= 2 && Integer.parseInt(values[0].toString()) == 0 && Integer.parseInt(values[1].toString()) == 0) {
                        criteria.setValues(null);
                    }
                });
            }
        }
        // 高级条件生成
        final QueryWrapper<SkuInfo> wrapper = this.buildQueryWrapper(pagination, Logic.AND, SkuInfo.class);
        // 通用查询条件
        final String condition = MapUtils.getString(pagination.toSearchMap(), "condition");
        if (StringUtils.isNotBlank(condition)) {
            wrapper.or().eq(ColumnConstant.ID, condition).or().like(ColumnConstant.NAME, condition);
        }
        return this.executeSelectPagination(pagination, wrapper, SkuInfoVO.class);
    }

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public SkuInfoVO selectById(Long skuId) throws Exception {
        return this.executeSelectById(skuId, SkuInfoVO.class);
    }

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public Map<String, Object> item(Long skuId) throws ExecutionException, InterruptedException {
        // TODO 优化，返回 VO
        final Map<String, Object> item = new HashMap<>();
        if (skuId == null) {
            return item;
        }
        // 1. 获取 sku 信息
        CompletableFuture<SkuInfo> infoFuture = CompletableFuture.supplyAsync(() -> {
            try {
                final SkuInfo info = this.baseMapper.selectById(skuId);
                if (info == null) {
                    return null;
                }
                item.putAll(BeanUtils.beanToMap(info));
                return info;
            } catch (Exception e) {
                Logger.error(log, () -> String.format("获取商品SKU[%d]信息失败，", skuId), e);
                return null;
            }
        }, executor);
        // 获取 spu 的销售属性组合
        final CompletableFuture<Void> saleAttrsFuture = infoFuture.thenAcceptAsync((info) -> {
            if (info == null) {
                return;
            }
            // 根据 spuId 获取所有的 skuId 集合
            final List<Long> skuIds;
            {
                final QueryWrapper<SkuInfo> wrapper = new QueryWrapper<>();
                wrapper.eq(ColumnConstant.SPU_ID, info.getSpuId());
                final List<SkuInfo> skuInfos = this.baseMapper.selectList(wrapper);
                skuIds = skuInfos.stream().map(SkuInfo::getId).collect(Collectors.toList());
            }
            // 根据 skuId 集合获取 sku 的销售属性
            final QueryWrapper<SkuSaleAttrValue> wrapper = new QueryWrapper<>();
            wrapper.in(ColumnConstant.SKU_ID, skuIds);
            final List<SkuSaleAttrValue> attrs = this.skuSaleAttrValueDao.selectList(wrapper);
            // 按照skuId分组
            final Map<Long, List<SkuSaleAttrValue>> saleAttrs = new HashMap<>();
            for (SkuSaleAttrValue attr : attrs) {
                final List<SkuSaleAttrValue> attrList = saleAttrs.computeIfAbsent(attr.getSkuId(), k -> new ArrayList<>());
                attrList.add(attr);
            }
            item.put("saleAttrs", saleAttrs);
        }, executor);
        // 获取spu的介绍
        CompletableFuture<Void> descFuture = infoFuture.thenAcceptAsync((info) -> {
            if (info == null) {
                return;
            }
            final SpuInfoDesc spuInfoDesc = spuInfoDescDao.selectById(info.getSpuId());
            item.put("introduce", spuInfoDesc.getIntroduce());
        }, executor);
        // 获取spu规格参数
        final CompletableFuture<Void> attrgroupFuture = infoFuture.thenAcceptAsync(info -> {
            if (info == null) {
                return;
            }
            final List<SpuAttrgroupDTO> attrgroup = this.spuInfoDao.selectSpuAttrGroup(info.getSpuId());
            item.put("attrgroup", attrgroup);
        });
        //等到所有任务都完成
        CompletableFuture.allOf(saleAttrsFuture, descFuture, attrgroupFuture).get();
        return item;
    }

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public List<SkuSaleAttrValueVO> saleAttrList(Long skuId) throws Exception {
        final QueryWrapper<SkuSaleAttrValue> wrapper = new QueryWrapper<>();
        wrapper.eq(ColumnConstant.SKU_ID, skuId);
        final List<SkuSaleAttrValue> skuSaleAttrValues = this.skuSaleAttrValueDao.selectList(wrapper);
        return BeanUtils.transformList(skuSaleAttrValues, SkuSaleAttrValueVO.class);
    }

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public List<SkuInfoVO> selectListByIds(List<Long> skuIds) throws Exception {
        if (CollectionUtils.isEmpty(skuIds)) {
            return Collections.EMPTY_LIST;
        }
        final QueryWrapper<SkuInfo> wrapper = new QueryWrapper<>();
        wrapper.in(ColumnConstant.ID, skuIds);
        final List<SkuInfo> skuInfoList = this.baseMapper.selectList(wrapper);
        return BeanUtils.transformList(skuInfoList, SkuInfoVO.class);
    }

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public List<SkuBriefInfoVO> selectSkuBriefInfoListByIds(List<Long> skuIds) {
        if (CollectionUtils.isEmpty(skuIds)) {
            return Collections.emptyList();
        }
        final QueryWrapper<SkuInfo> wrapper = new QueryWrapper<>();
        wrapper.in(ColumnConstant.ID, skuIds);
        final List<SkuInfo> skuList = this.baseMapper.selectList(wrapper);
        return skuList.stream().map(sku -> {
            final SkuBriefInfoVO vo = new SkuBriefInfoVO();
            vo.setId(String.valueOf(sku.getId()));
            vo.setPrice(sku.getPrice().doubleValue());
            vo.setDefaultImage(sku.getDefaultImage());
            vo.setPublished(Published.decide(sku.getPublished()) == Published.UP);
            return vo;
        }).collect(Collectors.toList());
    }

}
